// ----------------------------------------------------------
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v.2.0. If a copy of the MPL
// was not distributed with this file, You can obtain one
// at http://mozilla.org/MPL/2.0/.
// ----------------------------------------------------------
// Codebase: https://github.com/ArKuznetsov/cpdb/
// ----------------------------------------------------------

#Использовать ClientSSH

Перем Адрес;           // - Строка       - адрес сервера SSH
Перем Пользователь;    // - Строка       - имя пользователя сервера SSH
Перем Соединение;      // - КлиентSSH    - соединение с SSH-сервером

Перем Лог;             // - Объект    - объект записи лога приложения

#Область ПрограммныйИнтерфейс

// Функция - возвращает адрес сервера SSH
//
// Возвращаемое значение:
//   Строка    - адрес сервера SSH
//
Функция Адрес() Экспорт

	Возврат Адрес;

КонецФункции // Адрес()

// Функция - возвращает имя пользователя сервера SSH
//
// Возвращаемое значение:
//   Строка    - имя пользователя сервера SSH
//
Функция Пользователь() Экспорт

	Возврат Пользователь;

КонецФункции // Пользователь()

// Функция - возвращает соединение с сервером SSH
//
// Возвращаемое значение:
//   КлиентSSH    - соединение с сервером SSH
//
Функция Соединение() Экспорт

	Возврат Соединение;

КонецФункции // Соединение()

// Создает соединение с сервером SSH с указанными параметрами
//
// Параметры:
//    _Адрес           - Строка    - адрес сервера SSH
//    _Пользователь    - Строка    - имя пользователя сервера SSH
//    Пароль           - Строка    - пароль пользователя сервера SSH
//                                   или пароль к файлу закрытого ключа (если указан параметр ПутьККлючу)
//    ПутьККлючу       - Строка    - путь к файлу закрытого ключа сервера SSH
//
Процедура УстановитьПараметрыСоединения(Знач _Адрес, Знач _Пользователь, Знач Пароль = "", Знач ПутьККлючу = "") Экспорт

	ЧастиАдреса = СтрРазделить(_Адрес, ":", Ложь);

	Адрес = ЧастиАдреса[0];
	Порт  = 22;
	Если ЧастиАдреса.ВГраница() > 0 Тогда
		Порт = Число(ЧастиАдреса[1]);
	КонецЕсли;

	Пользователь = _Пользователь;

	Соединение = Новый КлиентSSH(Адрес, Порт, Пользователь, Пароль);
	Если ЗначениеЗаполнено(ПутьККлючу) Тогда
		Соединение = Новый КлиентSSH(Адрес, Порт, Пользователь, "");
		Соединение.УстановитьКлюч(ПутьККлючу, Пароль);
	Иначе
		Соединение = Новый КлиентSSH(Адрес, Порт, Пользователь, Пароль);
	КонецЕсли;

КонецПроцедуры // УстановитьПараметрыСоединения()

// Создает каталог на сервере SFTP
//
// Параметры:
//   ЦелевойПуть    - Строка       - путь к создаваемому каталогу
//
Процедура СоздатьКаталог(Знач ЦелевойПуть) Экспорт

	Попытка
		ФайлыНаСервере = Соединение.ПолучитьScp();
		
		ФайлыНаСервере.СоздатьКаталог(ЦелевойПуть);

		Лог.Информация("Создан каталог ""%1"" на SFTP-сервере", ЦелевойПуть);
	Исключение
		Если ТипЗнч(ФайлыНаСервере) = Тип("СоединениеSCP") Тогда
			ФайлыНаСервере.Отключиться();
		КонецЕсли;

		ТекстОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
		ТекстОшибки = СтрШаблон("Ошибка при создании каталога ""%1"" на SFTP-сервере: %2%3",
		                        ЦелевойПуть,
		                        Символы.ПС,
		                        ТекстОшибки);
		ВызватьИсключение ТекстОшибки;
	КонецПопытки;
	
	ФайлыНаСервере.Отключиться();

КонецПроцедуры // СоздатьКаталог()

// Процедура - отправляет файл на сервер SFTP
//
// Параметры:
//   ПутьКФайлу       - Строка       - путь к отправляемому файлу
//   ЦелевойПуть      - Строка       - путь к каталогу на сервере SFTP, куда будет загружен файл
//   Перезаписывать   - Булево       - перезаписать файл на сервере SFTP при загрузке
//
Процедура ОтправитьФайл(Знач ПутьКФайлу, Знач ЦелевойПуть, Перезаписывать = Ложь) Экспорт
	
	ПутьКФайлу = ФС.ПолныйПуть(ПутьКФайлу);

	Лог.Информация("Начало отправки файла на SFTP-сервер ""%1"" -> ""%2""", ПутьКФайлу, ЦелевойПуть);

	ИсходныйФайл = Новый Файл(ПутьКФайлу);
	
	Попытка
		ФайлыНаСервере = Соединение.ПолучитьScp();
		
		ФайлыНаСервере.ОтправитьФайл(ИсходныйФайл.ПолноеИмя,
		                             СтрШаблон("%1/%2", ЦелевойПуть, ИсходныйФайл.Имя),
		                             Перезаписывать);

		Лог.Информация("Файл загружен на SFTP-сервер ""%1"" -> ""%2""", ПутьКФайлу, ЦелевойПуть);
	Исключение
		Если ТипЗнч(ФайлыНаСервере) = Тип("СоединениеSCP") Тогда
			ФайлыНаСервере.Отключиться();
		КонецЕсли;

		ТекстОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
		ТекстОшибки = СтрШаблон("Ошибка загрузки файла ""%1"" на SFTP-сервер в ""%2/%1"":%3%4",
		                        ИсходныйФайл.Имя,
		                        ЦелевойПуть,
		                        Символы.ПС,
		                        ТекстОшибки);
		ВызватьИсключение ТекстОшибки;
	КонецПопытки;

	ФайлыНаСервере.Отключиться();

КонецПроцедуры // ОтправитьФайл()

// Процедура - получает файл с сервера SFTP
//
// Параметры:
//   ПутьНаСервере      - Строка       - расположение файла на сервере SFTP
//   ЦелевойКаталог     - Строка       - путь к каталогу, куда будет загружен файл
//   УдалитьИсточник    - Булево       - Истина - удалить файл после загрузки
//
// Возвращаемое значение:
//   Строка    - путь к полученному файлу
//
Функция ПолучитьФайл(Знач ПутьНаСервере, Знач ЦелевойКаталог, УдалитьИсточник = Ложь) Экспорт
	
	ЧастиПути = РаботаСФайлами.ЧастиПути(ПутьНаСервере);

	ЦелевойПуть = ОбъединитьПути(ЦелевойКаталог, ЧастиПути.Имя);

	ЦелевойПуть = ФС.ПолныйПуть(ЦелевойПуть);

	Лог.Информация("Начало получения файла c SFTP-сервера ""%1"" -> ""%2""", ПутьНаСервере, ЦелевойПуть);

	Попытка
		ФайлыНаСервере = Соединение.ПолучитьScp();
		
		ФайлыНаСервере.ПолучитьФайл(ПутьНаСервере, ЦелевойПуть);

		Лог.Информация("Файл ""%1"" получен c SFTP-сервера", ЦелевойПуть);
	Исключение
		Если ТипЗнч(ФайлыНаСервере) = Тип("СоединениеSCP") Тогда
			ФайлыНаСервере.Отключиться();
		КонецЕсли;

		ТекстОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
		ТекстОшибки = СтрШаблон("Ошибка получения файла ""%1"" c SFTP-сервера: %2%3",
		                        ПутьНаСервере,
		                        Символы.ПС,
		                        ТекстОшибки);
		ВызватьИсключение ТекстОшибки;
	КонецПопытки;

	ФайлыНаСервере.Отключиться();

	Если УдалитьИсточник Тогда
		УдалитьФайл(ПутьНаСервере);
	КонецЕсли;
	
	Возврат ЦелевойПуть;

КонецФункции // ПолучитьФайл()

// Функция - проверяет существование файла / каталога на сервере SFTP
//
// Параметры:
//   ПутьНаДиске    - Строка    - расположение файла на сервере SFTP
//
// Возвращаемое значение:
//   Булево    - Истина - файл / каталог существует
//
Функция Существует(Знач ПутьНаДиске) Экспорт
	
	Результат = Ложь;

	Попытка
		ФайлыНаСервере = Соединение.ПолучитьScp();
		Результат = ФайлыНаСервере.Существует(ПутьНаДиске);
	Исключение
		Если ТипЗнч(ФайлыНаСервере) = Тип("СоединениеSCP") Тогда
			ФайлыНаСервере.Отключиться();
		КонецЕсли;

		ТекстОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
		ТекстОшибки = СтрШаблон("Ошибка проверки существования файла ""%1"" на сервере SFTP: %2%3",
		                        ПутьНаДиске,
		                        Символы.ПС,
		                        ТекстОшибки);
		ВызватьИсключение ТекстОшибки;
	КонецПопытки;

	ФайлыНаСервере.Отключиться();

	Возврат Результат;

КонецФункции // Существует()

// Процедура - удаляет файл на сервере SFTP
//
// Параметры:
//   ПутьНаДиске    - Строка    - расположение файла на сервере SFTP
//
Процедура УдалитьФайл(Знач ПутьНаДиске) Экспорт
	
	Попытка
		ФайлыНаСервере = Соединение.ПолучитьScp();

		ФайлыНаСервере.УдалитьФайл(ПутьНаДиске);

		Лог.Информация("Удален файл ""%1"" на сервере SFTP", ПутьНаДиске);
	Исключение
		Если ТипЗнч(ФайлыНаСервере) = Тип("СоединениеSCP") Тогда
			ФайлыНаСервере.Отключиться();
		КонецЕсли;

		ТекстОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
		ТекстОшибки = СтрШаблон("Ошибка удаления файла ""%1"" на сервере SFTP: %2%3",
		                        ПутьНаДиске,
		                        Символы.ПС,
		                        ТекстОшибки);
		ВызватьИсключение ТекстОшибки;
	КонецПопытки;

	ФайлыНаСервере.Отключиться();

КонецПроцедуры // УдалитьФайл()

// Процедура - удаляет каталог на сервере SFTP
//
// Параметры:
//   ПутьНаДиске    - Строка    - расположение каталога на сервере SFTP
//
Процедура УдалитьКаталог(Знач ПутьНаДиске) Экспорт
	
	Попытка
		ФайлыНаСервере = Соединение.ПолучитьScp();

		ФайлыНаСервере.УдалитьКаталог(ПутьНаДиске);

		Лог.Информация("Удален каталог ""%1"" на сервере SFTP", ПутьНаДиске);
	Исключение
		Если ТипЗнч(ФайлыНаСервере) = Тип("СоединениеSCP") Тогда
			ФайлыНаСервере.Отключиться();
		КонецЕсли;

		ТекстОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
		ТекстОшибки = СтрШаблон("Ошибка удаления каталога ""%1"" на сервере SFTP: %2%3",
		                        ПутьНаДиске,
		                        Символы.ПС,
		                        ТекстОшибки);
		ВызватьИсключение ТекстОшибки;
	КонецПопытки;

	ФайлыНаСервере.Отключиться();

КонецПроцедуры // УдалитьКаталог()

#КонецОбласти // ПрограммныйИнтерфейс

#Область ОбработчикиСобытий

// Процедура - обработчик события "ПриСозданииОбъекта"
//
// Параметры:
//    _Адрес           - Строка    - адрес сервера SSH
//    _Пользователь    - Строка    - имя пользователя сервера SSH
//    Пароль           - Строка    - пароль пользователя сервера SSH
//                                   или пароль к закрытому ключу (если указан ключ)
//    ПутьККлючу       - Строка    - путь к файлу закрытого ключа сервера SSH
//
// BSLLS:UnusedLocalMethod-off
Процедура ПриСозданииОбъекта(Знач _Адрес, Знач _Пользователь, Знач Пароль = "", Знач ПутьККлючу = "") Экспорт

	Лог = ПараметрыСистемы.Лог();

	УстановитьПараметрыСоединения(_Адрес, _Пользователь, Пароль, ПутьККлючу);

КонецПроцедуры // ПриСозданииОбъекта()
// BSLLS:UnusedLocalMethod-on

#КонецОбласти // ОбработчикиСобытий
